using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;

namespace HB.MVVM
{
    /// <summary>
    /// 该基类不会主动调用OnPropertyChanged，VM所属项目需安装PropertyChanged.Fody
    /// </summary>
    public class ViewModelBaseFody : INotifyPropertyChanged, IDisposable
    {
#if NET40 || NET45
        #region DataContext方法

        /// <summary>
        /// 设置DataContext，页面Unload自动DisConnect
        /// </summary>
        /// <param name="element"></param>
        /// <param name="autoDisConnectEvent">界面unload后自动断开vm连接</param>
        /// 
        public void Connect(FrameworkElement element, bool autoDisConnectEvent = false)
        {
            this.View = element;
            this.Dispatcher = element.Dispatcher;
            this.AutoDisConnectEvent = autoDisConnectEvent;
            element.Loaded += VM_Init;
            element.Unloaded += Element_Unloaded;
            element.DataContext = this;
            VMConnectCount += 1;
        }

        private void Element_Unloaded(object sender, RoutedEventArgs e)
        {
            if (AutoDisConnectEvent)
            {
                var element = sender as FrameworkElement;
                element.Loaded -= VM_Init;
                element.Unloaded -= Element_Unloaded;
                element.DataContext = null;
                VMConnectCount -= 1;
                View = null;
                if (VMConnectCount < 1)
                {
                    this.Dispatcher = null;
                }
            }

            VM_UnInit(sender, e);
        }
        bool AutoDisConnectEvent { get; set; }
        public FrameworkElement View { get; set; }
        /// <summary>
        /// 使用Connect方法绑定时，Dispatcher将自动关联
        /// </summary>
        public System.Windows.Threading.Dispatcher Dispatcher;
        /// <summary>
        /// 需要与page或window loaded事件同步的操作，可重载
        /// </summary>
        /// <param name="sender">FrameworkElement</param>
        /// <param name="e"></param>
        public virtual void VM_Init(object sender, RoutedEventArgs e)
        {

        }
        /// <summary>
        /// 需要与page或window Unloaded事件同步的操作，可重载
        /// </summary>
        /// <param name="sender">FrameworkElement</param>
        /// <param name="e"></param>
        public virtual void VM_UnInit(object sender, RoutedEventArgs e)
        {

        }
        /// <summary>
        /// 连接VM的页面数
        /// </summary>
        public int VMConnectCount { get; private set; }
        #endregion
#endif
        #region 事件
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string name)//不变
        {
            if (dicAction?.ContainsKey(name) == true)
            {
                dicAction[name].Invoke();
            }
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
        Dictionary<string, Action> dicAction = null;

        /// <summary>
        /// 为属性更改注册通知事件，如多次注册，只保留最后一个
        /// </summary>
        /// <param name="properityName"></param>
        /// <param name="changedAction"></param>
        public void RegisterChangedEvent(string properityName, Action changedAction)
        {
            if (dicAction == null) { dicAction = new Dictionary<string, Action>(); }
            dicAction[properityName] = changedAction;
        }
        #endregion



        #region 命令
        /// <summary>
        /// 获取命令，设置初始值，在vm中单例
        /// </summary>
        /// <param name="A">命令主体函数</param>
        /// <param name="canExecFunc">执行条件，若为null则全允许</param>
        /// <param name="key"></param>
        /// <returns></returns>
        public ICommand GetCommand(Action A, Func<bool> canExecFunc = null, [CallerMemberName] string key = null)
        {
            if (key == null) { return null; }
            if (dicCmd == null) { dicCmd = new Dictionary<string, ICommand>(); }
            if (!dicCmd.ContainsKey(key))
            {
                SimpleCommand cmd = new SimpleCommand(A, canExecFunc);
                dicCmd[key] = cmd;
            }
            return dicCmd[key];
        }
        /// <summary>
        /// 获取命令，设置初始值，在vm中单例
        /// </summary>
        /// <param name="A">命令主体函数</param>
        /// <param name="canExecFunc">执行条件，若为null则全允许</param>
        /// <param name="key"></param>
        /// <returns></returns>
        public ICommand GetCommand<T>(Action<T> A, Func<T, bool> canExecFunc = null, [CallerMemberName] string key = null)
        {
            if (key == null) { return null; }
            if (dicCmd == null) { dicCmd = new Dictionary<string, ICommand>(); }
            if (!dicCmd.ContainsKey(key))
            {
                SimpleCommand<T> cmd = new SimpleCommand<T>(A, canExecFunc);
                dicCmd[key] = cmd;
            }
            return dicCmd[key];
        }
        #endregion



        //command 
        Dictionary<string, ICommand> dicCmd = null;
        //简易IOC部分
        Dictionary<string, object> dicIoc = null;



        #region IOC部分
        /// <summary>
        /// 注册对象,
        /// </summary>
        /// <typeparam name="T2"></typeparam>
        /// <param name="obj"></param>
        /// <param name="key">if key==null,will use empty key</param>
        /// <exception cref="Exception"></exception>
        public void IocRegister<T2>(T2 obj, string key = null)
        {
            if (obj == null) { throw new NullReferenceException("null object is not support"); }
            if (dicIoc == null) { dicIoc = new Dictionary<string, object>(); }
            string kv = $"{typeof(T2).FullName}-{key}";
            if (dicIoc.ContainsKey(kv))
            {
                throw new Exception("object or key alread exist");
            }
            dicIoc[kv] = obj;
        }
        /// <summary>
        /// 获取对象
        /// </summary>
        /// <typeparam name="T2"></typeparam>
        /// <param name="key">if key==null,will use empty key</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public T2 IocResolve<T2>(string key = null)
        {
            if (dicIoc == null) { throw new Exception("please register first"); }
            string kv = $"{typeof(T2).FullName}-{key}";
            if (dicIoc.ContainsKey(kv))
            {
                return (T2)dicIoc[kv];
            }
            else
            {
                throw new Exception("please register first");
            }
        }
        /// <summary>
        /// 获取并输出到指定对象
        /// </summary>
        /// <typeparam name="T2"></typeparam>
        /// <param name="target"></param>
        /// <param name="key"></param>
        public void IocResolve<T2>(out T2 target, string key = null)
        {
            target = IocResolve<T2>(key);
        }
        /// <summary>
        /// 清理容器
        /// </summary>
        public void IocClear()
        {
            if (dicIoc != null)
            {
                dicIoc.Clear();
            }
        }


        #endregion
        /// <summary>
        /// 手动清理托管的变量存储
        /// </summary>
        public void Dispose()
        {

            dicCmd?.Clear();
            dicIoc?.Clear();
        }
    }
}
